using System;
using System.Collections.Generic;
using System.Text;

namespace Scheduler
{
    public class RMT 
    {
        /*
         * The object of this class holds information about an RMT. 
         * These information are:
         * RMT'name (String name)
         * The list of therapies provided by this RMT 
         * (LinkedList<Therapy> providingThers)
         * The list of the time slots that this RMT is 
         * available (LinkedList<TimeSlot> availableTimes)
         * Flag that is true if the RMT is also the administator. false 
         * otherwise (Boolean isAdmin)
         * The list that holds the information about the work schedule 
         * of this RMT (LinkedList<WorkSched> schedule)
         */

        private String name;
        private String id;
        private Boolean isAdmin;
        private LinkedList<Therapy> providingThers;
        private LinkedList<TimeSlot> availableTimes;

        public RMT()
        {
            name = "";
            id = "";
            isAdmin = false;
            providingThers = new LinkedList<Therapy>();
            availableTimes = new LinkedList<TimeSlot>();
        }

        public RMT(Database db, String rmtID) : this()
        {
            if (rmtID == null || rmtID == "" || db == null)
                return;
            RMT tempRMT = db.readRMT(rmtID);
            if (tempRMT == null)
                return;
            this.Name = tempRMT.Name;
            this.ID = tempRMT.ID;
            this.IsAdmin = tempRMT.IsAdmin;
            this.providingThers = tempRMT.providingThers;
            this.availableTimes = tempRMT.availableTimes;
        }

        public RMT(String rmtID, String rmtName, Boolean admin) : this()
        {
            name = rmtName;
            id = rmtID;
            isAdmin = admin;
            providingThers = new LinkedList<Therapy>();
            availableTimes = new LinkedList<TimeSlot>();
        }

        public String Name
        {
            get { return name; }
            set { name = String.Copy(value); }
        }

        public String ID
        {
            get { return id; }
            set { id = String.Copy(value); }
        }

        public Boolean IsAdmin
        {
            get { return isAdmin; }
            set { isAdmin = value; }
        }

        public LinkedList<Therapy> TherapyList
        {
            get { return providingThers; }
        }

        public LinkedList<TimeSlot> TimeList
        {
            get { return availableTimes; }
        }

        /*
         * This method returns a String which displays detailed information
         * about a single therapy as well as the RMT's name. 
         * The therapy's value is taken as a parameter (String desiredTherpay)
         */
        internal String displayOneTherapy(String desiredTherapy)
        {
            foreach (Therapy curTher in this.TherapyList) 
            {
                if (curTher.Name == desiredTherapy)
                {
                    return "RMT: " + this.Name + "\r\r\n" + curTher.ToString(); 
                }

            }
            return "RMT does not provide " + desiredTherapy;
        }


        /*
         * This method returns a String which contains detailed information
         * on all the Therapies that are provided by this RMT as well as the
         * RMT name.
         */ 
        internal String displayAllTherapies()
        {
            String result = "RMT: " + this.Name + "\r\r\n";
            if (this.TherapyList.Count == 0)
            {
                return "RMT " + this.Name + " Does not provide any therapies at this time.";
            }
            else
            {
                foreach (Therapy curTher in this.TherapyList)
                {
                    result += curTher.ToString();

                }
            }
            return result;
        }

        /*
         * This method takes (String desiredTherpay) as a parameter and returns
         * true if this RMT provides that therapy. 
         * (i.e. if the therapy exists in the RMT's TherapyList)
         * Returns false otherwise.
         */ 
        internal Boolean doesProvideTher(String desiredTherapy)
        {
            Boolean doesProvide = false;
            foreach (Therapy curTher in this.TherapyList) 
            {
                if (curTher.Name == desiredTherapy)
                {
                    doesProvide = true;
                    break;
                }
            }
            return doesProvide;
        }

        /*
         * remove the given therapy price from the given therapy
         */ 
        public void removeTherapyPrice( Database db, String TherapyID, TherapyPrice therapyPrice)
        {
            foreach (Therapy curTher in TherapyList)
            {
                if (curTher.TherapyID == TherapyID)
                {
                    if (curTher.PriceList.Contains(therapyPrice))
                    {
                        curTher.PriceList.Remove(therapyPrice);
                        therapyPrice.removeFromDatabase(db, ID, TherapyID);
                        break;
                    }
                }
            }
        }
        
        /*
         * This method takes a therapy name and a duration value and validates if 
         * this RMT provides this therapy in the given duration.
         * If valid, it sets the (our price) to the corresponding price of the 
         * therapy and value and returns true.
         * If unvalid sets the price to -1 and returns false.
         */ 
        public Boolean isDurationValid(String therName, int duration, out int price) 
        {
            Boolean isValid = false;
            price = -1;
            TherapyPrice curTherPrice = new TherapyPrice(duration, 0);
            foreach (Therapy curTher in this.TherapyList) 
            {
                if (curTher.Name == therName) 
                {
                    if (curTher.PriceList.Contains(curTherPrice))
                    {
                        price = curTher.PriceList.Find(curTherPrice).Value.Price;
                        isValid = true;
                    }
                }
            }
         
            return isValid;
        }

        /*
         * This method takes a new TimeSlot as a parameter and adds it to
         * the TimeList of this RMT if it is not already in the list.
         * Returns true on success, false otherwise.
         */ 
        public Boolean addTimeSlot(Database db, TimeSlot newTS) 
        {
            if (!this.TimeList.Contains(newTS))
            {
                this.TimeList.AddFirst(newTS);
                this.writeToDatabase(db);
                return true;
            }
            return false;
        }

        /*
         * This method takes a TimeSlot remTS and removes it from the 
         * TimeList of this RMT. It also calls functions to update the
         * database.
         * Returns true on success, false otherwise.
         */
        public Boolean removeTimeSlot(Database db, TimeSlot remTS)
        {
            if (this.TimeList.Contains(remTS))
            {
                this.TimeList.Remove(remTS);
                db.writeRMT(this);
                return true;
            }
            return false;
        }


        public void writeToDatabase(Database db)
        {
            db.writeRMT(this);
            foreach (Therapy curTher in TherapyList)
            {
                curTher.writeToDatabase(db, this.id);
            }
        }

        /*
         * This method adds a new Therapy newTher to the list of the therapies that
         * this RMT is already providing. It then calls functions to update
         * the database as well.
         */ 

        public void addTherapy(Database db, Therapy newTher)
        {
            // Check to see if this RMT already performs this therapy.
            // If she does not, then add the therapy and all its data to the
            // list of therapies she provides.
            // If she does provide this therapy already, then just add the new price list
            // found in the newTher object to the existing price list for this existing
            // therapy

            // RMT does not perform this therapy
            if (!this.TherapyList.Contains(newTher))
            {
                this.TherapyList.AddLast(newTher);
                this.writeToDatabase(db);
            }
            // RMT already performes this therapy
            else
            {
               // this.TherapyList.Find(newTher).Value.removeFromDatabase(db, ID);
               // this.TherapyList.Remove(TherapyList.Find(newTher).Value);
               // this.TherapyList.AddLast(newTher);

                Therapy existingTher = this.TherapyList.Find(newTher).Value;
                foreach (TherapyPrice price in newTher.PriceList)
                    existingTher.PriceList.AddLast(price);
                this.writeToDatabase(db);
            }

        }

        /*
         * This method removes a Therapy that its ID is provided as therID
         * from the list of the therapies that this RMT is already providing. 
         * It then calls functions to update the database as well.
         */ 
        public void removeTherapy(Database db, String therID)
        {
            foreach (Therapy curTher in TherapyList) 
            {
                if (curTher.TherapyID == therID) 
                {
                    curTher.removeFromDatabase(db, this.ID);
                    this.TherapyList.Remove(curTher);
                    this.writeToDatabase(db);
                    break;
                }
            }   
        }


        public void removeRMT(Database db)
        {
            foreach (Therapy curTher in this.TherapyList)
            {
                curTher.removeFromDatabase(db, ID);
            }
            db.removeRMT(this.ID);    
        }
        
        public override bool Equals(object obj)
        {
            if (obj is RMT)
                return (this.Name == ((RMT)obj).Name);
            else return false;
        }

        /*
         * This method adds the schedule of the RMT to the schedule of the
         * rooms. If one room doesn't have free space for a timeSlot then
         * it checks other rooms in the list.
         */ 
        internal void addSchedule(Database db, LinkedList<Room> roomList)
        {
            foreach (TimeSlot curTS in this.TimeList)
            {
                foreach (Room curRoom in roomList) 
                {
                    if (curRoom.addRmtSched(db, this, curTS))
                    {
                        break;
                    }   
                }
            }
        }

        /*
         * Reads the names of the all available RMTs from the database.
         */ 
        public static LinkedList<String> readAllRMTs_Name(Database db)
        {
            return db.readAllRMTs_Name();
        }

        /*
         * Reads the IDs of the all available RMTs from the database.
         */
        public static LinkedList<String> readAllRMTs_ID(Database db)
        {
            return db.readAllRMTs_ID();
        }
    }
}
